#!/usr/bin/python

# Nixie Meter app for MacOS
# Copyright (c) 2018 Kouichi Kuroi / q61.org
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import subprocess
import time
import serial
import math
import sys
import multiprocessing

cores = multiprocessing.cpu_count()

def readConfig():
    rt = {}
    with open('config.txt', 'r') as conffile:
        lines = conffile.readlines()
        for l in lines:
            if l[0] == '#':
                continue
            keyval = l.rstrip('\n').split('=')
            if len(keyval) != 2:
                continue
            key = keyval[0].strip()
            val = keyval[1].strip()
            if len(key) < 1:
                continue
            rt[key] = val
    return rt

def doCommand(dev, cmd):
    dev.write(cmd)
    rt = ''
    while True:
        r = dev.read(1)
        if r == '!':
            break
        rt += r
    # print cmd, rt
    return rt

def doCommand_m(dev, meter, val):
    cmd = 'm' + str(meter) + str(val / 100 % 10) + str(val / 10 % 10) + str(val % 10)
    return doCommand(dev, cmd)


cfg = readConfig()
if not 'device' in cfg:
    print("no device specified.")
    exit(1)
if 'cores' in cfg:
    cores = cfg['cores']

while True:
    try:
        s = serial.Serial(port=cfg['device'], baudrate=19200)
        time.sleep(10)

        while True:
            pso = subprocess.check_output(['ps', 'Ax', '-o%cpu,rss'])
            cpu = 0.0
            mem = 0
            for psline in pso.splitlines():
                tok = psline.split()
                if (tok[0] != "%CPU"):
                    cpu += float(tok[0])
                    mem += int(tok[1])

            mpo = subprocess.check_output(['memory_pressure', '-Q'])
            memfree = 100
            for mpline in mpo.splitlines():
                tok = mpline.split()
                if (tok[0] == "System-wide"):
                    for t in tok:
                        if (t.endswith("%")):
                            memfree = int(t[:-1])

            cpui = int(round(cpu / cores))
            memi = 100 - memfree
            doCommand_m(s, 0, cpui)
            doCommand_m(s, 1, memi)

            time.sleep(0.5)

    except serial.serialutil.SerialException as e:
        print("Exception: ", e)

    time.sleep(10)
    
